#pragma once

#include "FileDedupe.h"
#include "ConfigParser.h"
#include "CompositeFilter.h"
#include "TaskLauncher.h"
#include "FormatQualifier.h"

#include "algorithms/SelectorAlgorithm.h"
#include "algorithms/ApproxAlgorithm.h"
#include "algorithms/HashAlgorithm.h"

#include <boost/program_options.hpp>

#include <string>
#include <memory>

typedef std::pair<std::map<std::string, std::string>, std::map<std::string, std::string>> 
        SettingsType;

namespace po = boost::program_options;

boost::program_options::options_description get_keys();

SettingsType get_settings(const std::string& config_file_name);

std::string get_config_file_name(const po::variables_map& options);

std::string get_hash_alg_name(const po::variables_map& options);
    
std::string get_approx_alg_name(const po::variables_map& options);

std::string get_img_comparison_alg_name(const po::variables_map& options);

double get_size_threshold(const po::variables_map& options,
                          const std::map<std::string, std::string>& variables);

double get_similarity_threshold(const po::variables_map& options,
       const std::map<std::string, std::string>& variables);

size_t get_thread_count(const po::variables_map& options,
                        const std::map<std::string, std::string>& variables);

std::shared_ptr<HashAlgorithm> get_hash_alg(const po::variables_map& options); 

std::shared_ptr<ApproxAlgorithm> get_approx_alg(const po::variables_map& options,
                                 const std::map<std::string, std::string>& variables);

std::shared_ptr<FormatQualifier> get_format_qualifier(const std::map<std::string, std::string>& formats);

std::shared_ptr<FilesystemReader> get_filesystem_reader(const po::variables_map& options,
                                  const std::map<std::string, std::string>& formats);

CompositeFilter get_filter(const po::variables_map& options,
                           const std::map<std::string, std::string>& variables,
                           const std::map<std::string, std::string>& formats);

std::shared_ptr<Printer> get_printer(const po::variables_map& options);

std::shared_ptr<TaskLauncher> get_task_launcher(const po::variables_map& options,
                              const std::map<std::string, std::string>& variables);

std::shared_ptr<Executor> get_executor(const po::variables_map& options,
                          const std::map<std::string, std::string>& variables);
            
std::shared_ptr<FileDedupe> get_file_dedupe(const po::variables_map& options,
                            const std::map<std::string, std::string>& variables,
                            const std::map<std::string, std::string>& formats);

